import logging
import sys
from contextvars import ContextVar
from pathlib import Path
from uuid import uuid4

from loguru import logger

from app.core.config import settings


class InterceptHandler(logging.Handler):
    """
    日志拦截处理器：将所有 Python 标准日志重定向到 Loguru

    工作原理：
    1. 继承自 logging.Handler
    2. 重写 emit 方法处理日志记录
    3. 将标准库日志转换为 Loguru 格式
    """

    def emit(self, record: logging.LogRecord) -> None:
        # 尝试获取日志级别名称
        try:
            level = logger.level(record.levelname).name
        except ValueError:
            level = record.levelno

        # 获取调用帧信息
        frame, depth = logging.currentframe(), 6
        while frame.f_code.co_filename == logging.__file__:
            frame = frame.f_back
            depth += 1

        # 使用 Loguru 记录日志
        logger.opt(depth=depth, exception=record.exc_info).log(
            level,
            record.getMessage()
        )


def setup_logging():
    """
    配置日志系统

    功能：
    1. 控制台彩色输出
    2. 文件日志轮转
    3. 错误日志单独存储
    4. 异步日志记录
    """
    # 步骤1：移除默认处理器
    logger.remove()

    # project_name = Path.cwd().name

    # 步骤2：定义日志格式
    log_format = (
        # 时间信息 + UUID
        "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> "
        # 日志级别，居中对齐
        "[<level>{level:.^8}</level>] "
        # 日志级别缩写，固定宽度为6字符，不足则用空格补齐
        # "[<level>{level: ^6.6}</level>] "
        # 进程ID
        "<red>{process:.<5}</red> "
        # 项目名称
        # f"[{project_name}, "
        # 线程、链路ID
        "[<yellow>{thread:.<5}</yellow>, {request_id:.<16.16}] "
        # 文件、函数和行号
        "<cyan>{name}:{function}:{line}</cyan> | "
        # 日志消息
        "<level>{message}</level>"
    )

    # 步骤3：配置控制台输出
    logger.add(
        sys.stdout,
        format=log_format,
        level=settings.LOG_LEVEL,
        # enqueue=True,  # 启用异步写入
        backtrace=False,  # 显示完整的异常回溯
        diagnose=True,  # 显示变量值等诊断信息
        colorize=True,  # 启用彩色输出
        filter=_logger_filter
    )

    if settings.LOG_DIR:
        # 步骤4：创建日志目录
        log_dir = Path(settings.LOG_DIR)
        if not log_dir.exists():
            log_dir.mkdir(parents=True)

        # 步骤5：配置常规日志文件
        logger.add(
            str(Path(log_dir, "log.log")),
            format=log_format,
            level="INFO",
            rotation="100 MB",
            retention="180 days",
            encoding="utf-8",
            enqueue=True,  # 异步写入
            filter=_logger_filter
        )

        # 步骤6：配置错误日志文件
        logger.add(
            str(Path(log_dir, "error.log")),
            format=log_format,
            level="ERROR",
            rotation="100 MB",
            retention="180 days",
            encoding="utf-8",
            enqueue=True,  # 异步写入
            filter=_logger_filter
        )

    # 步骤7：配置 标准库日志 / 第三方库日志
    logger_name_list = [name for name in logging.root.manager.loggerDict]
    for logger_name in logger_name_list:
        _logger = logging.getLogger(logger_name)
        _logger.setLevel(logging.INFO)
        _logger.handlers = []
        if '.' not in logger_name:
            _logger.addHandler(InterceptHandler())

    # logger.info("Log system initialization completed")


# 使用任务request_id来实现全链路日志追踪
_x_request_id: ContextVar[str] = ContextVar('x_request_id', default="None")  # 请求ID


def set_trace_id(req_id: str) -> ContextVar[str]:
    """设置请求ID，外部需要的时候，可以调用该方法设置
    Returns:
        ContextVar[str]: _description_
    """
    if not req_id:
        req_id = uuid4().hex
    _x_request_id.set(req_id)
    return _x_request_id


def get_trace_id() -> str:
    """获取请求ID，外部需要的时候，可以调用该方法获取
    Returns:
        str: _description_
    """
    return _x_request_id.get()


def _logger_filter(record):
    record['request_id'] = f"{_x_request_id.get()}"
    return True


__all__ = [
    "logger",
    "setup_logging",
    "set_trace_id"
]
